<? 

/*
Константы для удобства.
Коды соответствуют символам в win-кодировке, но это "совпадение":) - на самом деле, скрипт кросскодировочный (win и koi).
*/

define("TAG1","\xAC");
define("TAG2","\xAD");
define("LAQUO","\xAB");
define("RAQUO","\xBB");
define("LDQUO","\x84");
define("RDQUO","\x93");
define("MDASH","\x97");
define("NDASH","\x96");
define("APOS","\xB4");
define("HELLIP","\x85");

// функция-заменялка для тегов

$Refs = array(); // буфер для хранения тегов
$RefsCntr = 0;   // счётчик буфера

function yyyTypo($x) {
	global $Refs, $RefsCntr;
	$Refs[] = StripSlashes($x[0]);
	return TAG1.($RefsCntr++).TAG2;
}

function zzzTypo($x) {
	global $Refs;
	return $Refs[$x[1]];
}

function TypoAll($text, $isHTML = true) {
	global $Refs,$RefsCntr;
	if($isHTML) {
		$Refs = array(); // сбрасываем буфер
		$RefsCntr = 0;   // счётчик буфера
		/*
		Вырезаем элементы, содержимое которых мы не должны преобразовывать:
		комментарии, скрипты, стили, ещё что-нибудь - по вкусу.
		Вырезанные блоки складируем в Refs при помощи функции xxxTypo()
		*/
		// комментарии
		$text = preg_replace_callback('{<!--.*?-->}s', 'yyyTypo', $text);
		$PrivateTags = "title|script|style|pre|textarea";
		$text = preg_replace_callback('{<\s*('.$PrivateTags.')[\s>].*?<\s*/\s*\1\s*>}is', 'yyyTypo', $text);
		// обычные теги
		$text = preg_replace_callback('{<(?:[^\'"\>]+|".*?"|\'.*?\')+>}s','yyyTypo',$text);
	}
	// ОК. Теперь займёмся кавычками 
    /*      
        ВЕЛИКОЕ ПРАВИЛО: Кавычки всегда прилегают к словам! 

        Открывающиеся кавычки 
        могут встречаться: 
            в начале строки, 
            после скобок "([{", 
            дефиса 
            пробелов, 
            ещё одной кавычки 
    */ 
    $prequote = '\s\(\[\{";-'; 
    $text = preg_replace('{^"}', LAQUO, $text); 
    $text = preg_replace('{(?<=['.$prequote.'])"}', LAQUO, $text); 

    // а это для тех, кто нарушает ВЕЛИКОЕ ПРАВИЛО 
    $text = preg_replace('{^((?:'.TAG1.'\d+'.TAG2.')+)"}', '\1'.LAQUO, $text); 
    $text = preg_replace('{(?<=['.$prequote.'])((?:'.TAG1.'\d+'.TAG2.')+)"}', '\1'.LAQUO, $text); 

    /*      
        Закрывающиеся кавычки - все остальные 
        Вы спросите - а как же тогда ставить знак дюйма? Очень просто - &quot;! 
    */ 
    $text = str_replace('"', RAQUO, $text); 

    // исправляем ошибки в расстановке кавычек типа ""... и ..."" 
    // (предполагаем, что не более двух-трёх кавык подряд) 
    $text = preg_replace('{'.LAQUO.RAQUO.'}', LAQUO.LAQUO, $text); 
    $text = preg_replace('{'.RAQUO.LAQUO.'}', RAQUO.RAQUO, $text); 

    //    вложенные кавыки 
    $i=0; // - это защита от зацикливания (оно возможно в случае неправильно расставленных кавычек) 
    while (($i++<10) && preg_match('{'.LAQUO.'(?:[^'.RAQUO.']*?)'.LAQUO.'}', $text)) 
        $text = preg_replace( 
            '{'.LAQUO.'([^'.RAQUO.']*?)'.LAQUO.'(.*?)'.RAQUO.'}s', 
            LAQUO.'\1'.LDQUO.'\2'.RDQUO, $text); 

    $i=0; 
    while (($i++<10) && preg_match('{'.RAQUO.'(?:[^'.LAQUO.']*?)'.RAQUO.'}', $text)) 
        $text = preg_replace( 
            '{'.RAQUO.'([^'.LAQUO.']*?)'.RAQUO.'}', 
            RDQUO.'\1'.RAQUO, $text); 

    // с кавычками закончили, займёмся мелкой типографикой 
    // тире: 
    $text = preg_replace('{^-+(?=\s)}',MDASH,$text); 
    $text = preg_replace('{(?<=[\s'.TAG2.'])-+(?=\s)}',MDASH,$text); 
    $text = str_replace(' '.MDASH,'&nbsp;'.MDASH,$text); 
    // ndash: 
    $text = preg_replace('{(?<=\d)-(?=\d)}',NDASH,$text); 
    // ...: 
    $text = str_replace('...',HELLIP,$text); 
    // апостроф: 
    $text = preg_replace('{(?<=\S)\'}',APOS,$text); 


    if($isHTML) 
    { 
        // возвращаем взятое обратно 
        while (preg_match('{'.TAG1.'.+?'.TAG2.'}', $text)) 
            $text = preg_replace_callback('{'.TAG1.'(.+?)'.TAG2.'}', 'zzzTypo', $text); 
    } 

    // заменяем коды символов на HTML-entities. 
    $text = str_replace( 
        array(LAQUO,RAQUO,LDQUO,RDQUO,MDASH,NDASH,HELLIP,APOS), 
        array('&laquo;','&raquo;','&bdquo;','&ldquo;','&#8212;','&#8211;','&hellip;','&#8217;'), 
        $text 
    ); 

    return $text; 
} 

?>